public class Cache {

	int numSets;
	int blockSize;

	int cacheHits = 0;
	int cacheMisses = 0;

	String writePolicy;

	Set[] sets;

	Cache(int numBlocks, int blockSz, int assoc, String replacementPolicy,
			String writePolicy) {
		numSets = (numBlocks) / assoc;
		blockSize = blockSz;

		this.writePolicy = writePolicy;

		sets = new Set[numSets];

		for (int i = 0; i < numSets; i++) {
			sets[i] = new Set(assoc, replacementPolicy);
		}
	}

	void read(long address) {

		//dividing by block size drops those bits from the address
		//we're in base 10, but the math is the same
		long tagAndIndex = address / blockSize;

		//the index is the remainder after dividing by the number of sets
		int index = (int) (tagAndIndex % numSets);
		
		//and the tag we get by dropping the index bits!
		long tag = tagAndIndex / numSets;

		if (sets[index].find(tag)) {
			cacheHits += 1;
		} else {
			cacheMisses += 1;
			sets[index].load(new Block(tag));
		}
	}

	void write(long address) {
		
		//dividing by block size drops those bits from the address
		//we're in base 10, but the math is the same
		long tagAndIndex = address / blockSize;

		//the index is the remainder after dividing by the number of sets
		int index = (int) (tagAndIndex % numSets);
		
		//and the tag we get by dropping the index bits!
		long tag = tagAndIndex / numSets;

		//the sets are put into the sets array with a position corresponding to their index..
		if (sets[index].find(tag)) {
			cacheHits += 1;
			sets[index].write();
		} else {
			cacheMisses += 1;

			// we only have write allocate on the write back policy atm.
			// if write allocate, we need to load the block
			if (writePolicy.equalsIgnoreCase("wb"))
                           
                            sets[index].load(new Block(tag));
		}
	}

	int getTagComparisons() {
		int temp = 0;

		for (int i = 0; i < sets.length; i++) {
			temp += sets[i].tagCompares;
		}

		return temp;
	}
        
        

        String getStats(int cacheSize, int assoc, String replacementPolicy)
        {
            String stats = "";
            
            //double test = (double)cacheHits/(cacheHits+cacheMisses);
            
            stats = "Cache: " + cacheSize + " Block: " + this.blockSize;
            stats += " Assoc: " + assoc + " Replace: " + replacementPolicy;
            stats += " Write: " + writePolicy;
            stats += "\nOverall cache hit ratio: " + 
                    Double.toString((double)cacheHits/(cacheHits+cacheMisses)) + "\n";
          
            String numTagComp = Integer.toString(this.getTagComparisons());
            stats += "Number of tag comparisons: " + numTagComp + "\n\n"; 
            
            return stats;
        }
        
}
